﻿using Clancy.Common.Extensions;
using Clancy.Interfaces;
using Clancy.Ui.Properties;
using Clancy.Ui.Views;
using ReactiveUI;
using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Windows;

namespace Clancy.Ui.ViewModels
{
    public class CameraManagerViewModel : ClancyEditorViewModelBase
    {
        private readonly BehaviorSubject<MonitorViewModel> m_SelectedSurveilanceBehaviorSubject = new BehaviorSubject<MonitorViewModel>(null);
        private readonly ISelectionManager m_SelectionManager;
        private readonly ObservableCollection<ISurveilanceObject> m_SurveilanceObjects = new ObservableCollection<ISurveilanceObject>();
        private ObservableAsPropertyHelper<MonitorViewModel> m_SelectedSurveilanceObjectHelper;
        private IReactiveDerivedList<MonitorViewModel> m_SurveilanceObjectViewModelsViewModels;

        public CameraManagerViewModel(IOperationalAdapterProvider operationalAdapterProvider, ISelectionManager selectionManager, ISurveilanceStorage surveilanceStorage)
            : base(operationalAdapterProvider, surveilanceStorage)
        {
            m_SelectionManager = selectionManager;

            InitProperties();

            CreateManagementCommands();

            FillRibbonCommands();

            RefreshOperationsAdapter();
        }

        public ReactiveCommand<object> CmdAddNewSurveilanceSource { get; private set; }

        public ReactiveCommand<object> CmdEditMotionDetectionZones { get; private set; }

        public ReactiveCommand<object> CmdLearnMotionThreshold { get; private set; }

        public ReactiveCommand<object> CmdRemoveSurveilanceSource { get; private set; }

        public ReactiveCommand<object> CmdShowAdvancedVideoSettings { get; private set; }

        public MonitorViewModel SelectedMonitor
        {
            get
            {
                if (m_SelectedSurveilanceObjectHelper == null)
                    return null;
                return m_SelectedSurveilanceObjectHelper.Value;
            }
            set
            {
                m_SelectedSurveilanceBehaviorSubject.OnNext(value);
            }
        }

        public IObservable<MonitorViewModel> SelectedMonitorViewModelObservable
        {
            get { return m_SelectedSurveilanceBehaviorSubject; }
        }

        public ObservableCollection<ISurveilanceObject> SurveilanceObjects
        {
            get { return m_SurveilanceObjects; }
        }

        public virtual IReactiveDerivedList<MonitorViewModel> SurveilanceObjectsViewModels
        {
            get { return m_SurveilanceObjectViewModelsViewModels; }
        }

        private ISurveilanceObject SelectedSurveilanceObject
        {
            get
            {
                if (SelectedMonitor == null)
                    return null;
                return SelectedMonitor.SurveilanceObject;
            }
        }

        protected override void DisposeElements()
        {
        }

        protected override void RefreshOperationsAdapter()
        {
            SurveilanceObjects.Clear();

            base.RefreshOperationsAdapter();

            AttachSurveilanceCollection();

            FillSurveilanceObjectBufferWithCurrentValues();
        }

        private static void ShowZonesEditor(ISurveilanceObject surveilanceObject)
        {
            if (surveilanceObject == null)
                return;

            ZoneEditorWindow zoneEditor = new ZoneEditorWindow();
            zoneEditor.ShowDialog();
        }

        private void AddSurveilanceToDisplayBuffer(IList items)
        {
            foreach (ISurveilanceObject survObj in items)
            {
                if (survObj == null)
                    continue;

                SurveilanceObjects.Add(survObj);
            }
        }

        private void AttachSurveilanceCollection()
        {
            AttachToCollection(SurveilanceStorage.SurveilanceObjects,
                items => AddSurveilanceToDisplayBuffer(items as IList),
                items => RemoveSurveilanceToDisplayBuffer(items as IList));
        }

        private void CreateManagementCommands()
        {
            CmdAddNewSurveilanceSource = ReactiveCommand.Create();
            CmdAddNewSurveilanceSource.Subscribe(_ => CreateNewVideoSource());
            DisposableRxElements.Add(CmdAddNewSurveilanceSource);

            CmdRemoveSurveilanceSource = ReactiveCommand.Create(m_SelectedSurveilanceBehaviorSubject.Select(selObj => selObj != null));
            CmdRemoveSurveilanceSource.Subscribe(_ =>
            {
                if (MessageBox.Show(Resources.ReallyRemoveSelectedVideoSource, "Delete...", MessageBoxButton.YesNo, MessageBoxImage.Question) != MessageBoxResult.Yes)
                    return;
                DeleteSelectedVideoSource();
            });
            DisposableRxElements.Add(CmdRemoveSurveilanceSource);

            CmdShowAdvancedVideoSettings = ReactiveCommand.Create(m_SelectedSurveilanceBehaviorSubject.Select(selObj => selObj != null));
            CmdShowAdvancedVideoSettings.Subscribe(async _ =>
            {
                if (SelectedSurveilanceObject == null)
                    return;

                await OperationAdapter.ShowAdvancedVideoDialog(SelectedSurveilanceObject);
            });
            DisposableRxElements.Add(CmdShowAdvancedVideoSettings);

            CmdEditMotionDetectionZones = ReactiveCommand.Create(m_SelectedSurveilanceBehaviorSubject.Select(selObj => selObj != null));
            CmdEditMotionDetectionZones.Subscribe(_ => ShowZonesEditor(SelectedSurveilanceObject));
            DisposableRxElements.Add(CmdEditMotionDetectionZones);

            CmdLearnMotionThreshold = ReactiveCommand.Create(m_SelectedSurveilanceBehaviorSubject.Select(selObj => selObj != null));
            CmdLearnMotionThreshold.Subscribe(_ => { });
            DisposableRxElements.Add(CmdLearnMotionThreshold);
        }

        private async void CreateNewVideoSource()
        {
            VideoSourceSelectionWindow dlg = new VideoSourceSelectionWindow();
            VideoSourceSelectionViewModel viewModel = new VideoSourceSelectionViewModel(OperationAdapter.GetAvailableSources());
            dlg.DataContext = viewModel;

            bool? dlgResult = dlg.ShowDialog();
            if ((dlgResult == null) || (!dlgResult.Value))
                return;

            if (viewModel.SelectedItem != null)
            {
                await OperationAdapter.AddNewSource(viewModel.SelectedItem);
            }
        }

        private async void DeleteSelectedVideoSource()
        {
            if (SelectedSurveilanceObject == null)
                return;

            await OperationAdapter.StopVideoStream(SelectedSurveilanceObject);
            await OperationAdapter.DeleteVideoSource(SelectedSurveilanceObject);
        }

        private void FillRibbonCommands()
        {
            InsertRibbonButton(Resources.RibbonTab_Basic, Resources.RibbonGroup_ManageVideoSources, Resources.RibbonElement_AddVideoSource, Resources.db_add_32.ToBitmapImage(), CmdAddNewSurveilanceSource);
            InsertRibbonButton(Resources.RibbonTab_Basic, Resources.RibbonGroup_ManageVideoSources, Resources.RibbonElement_RemoveVideoSource, Resources.edit_delete_9_32.ToBitmapImage(), CmdRemoveSurveilanceSource);
            InsertRibbonButton(Resources.RibbonTab_Basic, Resources.RibbonGroup_ManageVideoSources, Resources.RibbonElement_ShowAdvancedSettings, Resources.document_properties_2_32.ToBitmapImage(), CmdShowAdvancedVideoSettings);

            InsertRibbonButton(Resources.RibbonTab_Basic, Resources.RibbonGroup_ManageVideoSources, Resources.RibbonElement_EditMotionDetectionZones, Resources.transform_crop_and_resize.ToBitmapImage(), CmdEditMotionDetectionZones);
            InsertRibbonButton(Resources.RibbonTab_Basic, Resources.RibbonGroup_ManageVideoSources, Resources.RibbonElement_LearnMotionThreshold, Resources.tools_wizard.ToBitmapImage(), CmdLearnMotionThreshold);
        }

        private void FillSurveilanceObjectBufferWithCurrentValues()
        {
            foreach (ISurveilanceObject surveilanceObject in SurveilanceStorage.SurveilanceObjects)
            {
                SurveilanceObjects.Add(surveilanceObject);
            }
        }

        private void InitProperties()
        {
            m_SurveilanceObjectViewModelsViewModels = SurveilanceObjects.CreateDerivedCollection(surveilanceObject =>
            {
                ISurveilanceStatus surveilanceStatus = OperationAdapter.GetSurveilance(surveilanceObject);
                MonitorViewModel monitorViewModel = new MonitorViewModel(surveilanceObject);
                surveilanceStatus.CurrentProcessedFrame.SubscribeOnDispatcher().Subscribe(monitorViewModel);
                return monitorViewModel;
            });
            DisposableRxElements.Add(m_SurveilanceObjectViewModelsViewModels);

            m_SelectedSurveilanceObjectHelper = new ObservableAsPropertyHelper<MonitorViewModel>(m_SelectedSurveilanceBehaviorSubject,
                _ =>
                {
                    m_SelectionManager.SetSelection(SelectedSurveilanceObject);
                    this.RaisePropertyChanged("SelectedSurveilanceObject");
                    this.RaisePropertyChanged("SelectedMonitor");
                });
            DisposableRxElements.Add(m_SelectedSurveilanceObjectHelper);
        }

        private void RemoveSurveilanceToDisplayBuffer(IList items)
        {
            foreach (ISurveilanceObject survObj in items)
            {
                if (survObj == null)
                    continue;

                OperationAdapter.StopVideoStream(survObj);
                SurveilanceObjects.Remove(survObj);
            }
        }
    }
}